home *** CD-ROM | disk | FTP | other *** search
/ 9-Digit Zip Code Directory / 9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO / z4src.zip / DIREAD.C < prev    next >
C/C++ Source or Header  |  1995-09-14  |  12KB  |  355 lines

  1. //----------------------------------------------------------------------------
  2. //                            MODULE DESCRIPTION
  3. //
  4. //  Module:    diread.c
  5. //   Title:    Data File I/O Library
  6. //  Notice:    John M. Weeder
  7. //                 Copyright (c) 1993. All rights reserved.
  8. //             This module contains proprietary information and should be 
  9. //                treated as confidential.
  10. //
  11. //----------------------------------------------------------------------------
  12. //                           MAINTENANCE HISTORY
  13. //
  14. // $Workfile$
  15. // $Revision$
  16. //   $Author$
  17. //     $Date$
  18. //      $Log$    
  19. //
  20. //----------------------------------------------------------------------------
  21. //                             MODULE NARRATIVE
  22. //
  23. //
  24. //    This module contains code to read from a data file.
  25. //
  26. //    The code in this module should be written entirely in C. 
  27. //    Do not use any C++ constructs.
  28. //
  29. //    This module is portable to:
  30. //        DOS 3.X+
  31. //        MS Windows 3.X+
  32. //        OS/2 2.X+
  33. //        OS/2 2.0 PM
  34. //        SCO UNIX.
  35. //
  36. //    The following compilers are supported:
  37. //        MSC 6.0A
  38. //        MSC/C++ 7.0
  39. //        Borland C++ 3.1 for DOS
  40. //        Borland C++ 1.0 for OS/2 2.X
  41. //        SCO UNIX cc
  42. //
  43. //----------------------------------------------------------------------------
  44. #include <di.h>
  45.  
  46.  
  47. //----------------------------------------------------------------------------
  48. //    Prototypes
  49. //----------------------------------------------------------------------------
  50. static VOID FN_L DioReadSearch(PBYTE, SIZET, PBYTE, SIZET, PLONG);
  51.  
  52.  
  53. //----------------------------------------------------------------------------
  54. //   Description:    Read from a random access file.
  55. //    Parameters:    hlf        Logical file handle.
  56. //                        pb            Buffer to read.
  57. //                        cb         Size of buffer to read.
  58. //                        pcb        If not null, this variable recieves the number of
  59. //                                    bytes read.
  60. //       Returns:    TRUE if successful.
  61. //----------------------------------------------------------------------------
  62. BOOL FN_E DioRead(HLF hlf, PBYTE pb, SIZET cb, PSIZET pcb)
  63. {
  64.     FPOS fpos, flen;
  65.  
  66.     if (pcb)
  67.         *pcb = 0;
  68.  
  69.     Assert(hlf >= 0 && hlf < MAX_LOGICAL_FILES);
  70.     Assert(di.logical[hlf].fUsed);
  71.     Assert(pb && cb);
  72.  
  73.     if ((di.logical[hlf].fl & (LF_ERROR|LF_EOF))
  74.     || (di.physical[di.logical[hlf].hpf].fl & LF_ERROR))
  75.         return FALSE;
  76.  
  77.     fpos = di.logical[hlf].fpos;            // Get actual offset into file and 
  78.     flen = di.logical[hlf].flen - fpos;    //  adjust length if needed.
  79.     if ((FPOS)cb > flen)
  80.         cb = (SIZET)flen;
  81.  
  82.     fpos += di.logical[hlf].fbase;            // Read data
  83.     if (!FileRead(di.logical[hlf].hf, pb, cb, fpos))
  84.         {
  85.         di.logical[hlf].fl |= LF_ERROR;    // If failed, set error flag
  86.         return FALSE;
  87.         }
  88.     di.logical[hlf].fpos += (FPOS)cb;        // Move file pointer
  89.     if (di.logical[hlf].fpos >= di.logical[hlf].flen)
  90.         di.logical[hlf].fl |= LF_EOF;
  91.     if (pcb)
  92.         *pcb = cb;
  93.     return TRUE;
  94. }
  95.  
  96.  
  97. //----------------------------------------------------------------------------
  98. //   Description:    Read a block.
  99. //                          This function also handles caching on a block by block
  100. //                        basis.
  101. //    Parameters:    hlf        Logical file handle
  102. //                        pb            Buffer to read block into.
  103. //                                    If null, the data is simply placed in the cache
  104. //                                    if one is present.
  105. //                                    Buffer is assumed to be of correct size
  106. //                        ppb        If not null, the variable recieves a pointer to
  107. //                                    the cache buffer containing the data which was
  108. //                                    read.
  109. //                        plBlock    If not null, this variable recieves the id of the
  110. //                                    block which was read.
  111. //       Returns:    TRUE if successful.
  112. //----------------------------------------------------------------------------
  113. BOOL FN_E DioReadBlock(HLF hlf, PBYTE pb, PBYTE _FAR_ *ppb, PLONG plBlock)
  114. {
  115.     SIZET cCache;                                // Number of cache buffers
  116.     LONG lBlock;                                // Block id being read
  117.     SIZET cBlock;                                // Size of a block
  118.     SIZET cbRead;                                // Number of bytes read
  119.     PCACHE pcacheReplace = NULL;            // New cache buffer for data
  120.     PCACHE pcacheFound = NULL;                // Cache buffer with data
  121.     PCACHE pcache;
  122.  
  123.     //
  124.     //    First, perform a bunch of parameter validation in case something
  125.     //    has failed.
  126.     //
  127.     Assert(hlf >= 0 && hlf < MAX_LOGICAL_FILES);
  128.     Assert(di.logical[hlf].fUsed);
  129.     Assert(di.logical[hlf].usBlockSize);
  130.     Assert((di.logical[hlf].fpos % (FPOS)di.logical[hlf].usBlockSize) == 0);
  131.     Assert(pb || ppb);
  132.  
  133.     //
  134.     //    Search through the cache looking for the block being read.
  135.     //    If found, return data and set usage for buffer to 1.
  136.     //    Increment the usage counter of all other used cache buffers.
  137.     //    At the same time, keep tracked of the oldest cache buffer in
  138.     //     cache we need to read data into it.
  139.     //
  140.     cBlock = (SIZET)di.logical[hlf].usBlockSize;
  141.     lBlock = (LONG)(di.logical[hlf].fpos / (FPOS)di.logical[hlf].usBlockSize);
  142.     cCache = di.logical[hlf].cCache;
  143.     if (plBlock)
  144.         *plBlock = lBlock;
  145.     if (cCache)
  146.         {
  147.         PBYTE pbCache = di.logical[hlf].pcache;
  148.         USHORT usUsage = 1;
  149.  
  150.         for (; cCache; --cCache)
  151.             {
  152.             pcache = (PCACHE)pbCache;
  153.             if (pcache->usUsage)
  154.                 {                                    // Is this the block we want?
  155.                 if (pcache->lBlock == lBlock)
  156.                     pcacheFound = pcache;    // If so, save a pointer to it
  157.                 else if (pcache->usUsage < 0xFFFF)
  158.                     pcache->usUsage++;          // Otherwise, bump usage count
  159.                 }
  160.                                                     // Watch for oldest or unused buffer
  161.             if (usUsage && (!pcache->usUsage || pcache->usUsage >= usUsage))
  162.                 {
  163.                 usUsage = pcache->usUsage;
  164.                 pcacheReplace = pcache;
  165.                 }
  166.             pbCache += sizeof(CACHE) - sizeof(BYTE) + cBlock;
  167.             }
  168.         if (pcacheFound)                        // If data was found in the cache
  169.             {                                        // Set usage count to 1 and return
  170.             if (ppb)                                //  data to the user
  171.                 *ppb = pcacheFound->bBuffer;
  172.             if (pb)
  173.                 memcpy(pb, pcacheFound->bBuffer, cBlock);
  174.             pcacheFound->usUsage = 1;
  175.             return TRUE;
  176.             }
  177.         }
  178.     //
  179.     //    Temporarily mark cache buffer as unused. 
  180.     //    Then read the data.
  181.     //
  182.     if (pb == NULL)                            // Make sure there is a buffer to
  183.         {                                            //  read into
  184.         Assert(pcacheReplace);
  185.         pb = pcacheReplace->bBuffer;
  186.         }
  187.     if (pcacheReplace)
  188.         pcacheReplace->usUsage = 0;
  189.     if (!DioRead(hlf, pb, cBlock, &cbRead))
  190.         return FALSE;
  191.     if (cBlock != cbRead)                    // If failed, set error flags
  192.         {
  193.         di.logical[hlf].fl |= LF_ERROR;    
  194.         return FALSE;
  195.         }
  196.     //
  197.     //    Update cache.
  198.     //
  199.     if (ppb)
  200.         {
  201.         if (pcacheReplace)
  202.             *ppb = pcacheReplace->bBuffer;
  203.         else
  204.             *ppb = pb;
  205.         }
  206.     if (pcacheReplace)
  207.         {
  208.         pcacheReplace->usUsage = 1;        // Update cache data
  209.         pcacheReplace->lBlock = lBlock;
  210.                                                     // Copy data to cache buffer
  211.         if (pb != pcacheReplace->bBuffer)
  212.             memcpy(pcacheReplace->bBuffer, pb, cBlock);
  213.         }
  214.     return TRUE;
  215. }
  216.  
  217.  
  218. //----------------------------------------------------------------------------
  219. //   Description:    Read first keyed record block. 
  220. //                          After the first read, the DioReadBlock() function may be
  221. //                        called to read successive blocks.
  222. //    Parameters:    hlf        Logical file handle
  223. //                        pbKey        Key data
  224. //                        cbKey        Size of key
  225. //                        pb            Buffer to read block into.
  226. //                                    If null, the buffer is simply placed in the cache
  227. //                                    if one is present.
  228. //                                    Buffer is assumed to be of correct size
  229. //                        ppb        If not null, the variable recieves a pointer to
  230. //                                    the cache buffer containing the data which was
  231. //                                    read.
  232. //                        plBlock    If not null, this variable recieves the id of the
  233. //                                    block which was read.
  234. //       Returns:    TRUE if successful.
  235. //----------------------------------------------------------------------------
  236. BOOL FN_E DioReadFirst(HLF hlf, PBYTE pbKey, SIZET cbKey, PBYTE pb, PBYTE _FAR_ *ppb, PLONG plBlock)
  237. {
  238.     LONG lBlock;
  239.  
  240.     if (!DioReadIndex(hlf, pbKey, cbKey, &lBlock))
  241.         return FALSE;
  242.     if (plBlock)
  243.         *plBlock = lBlock;
  244.     Assert(pb || ppb);
  245.     if (!DioSeekBlock(hlf, lBlock)
  246.     || !DioReadBlock(hlf, pb, ppb, &lBlock))
  247.         return FALSE;
  248.     return TRUE;
  249. }
  250.  
  251.  
  252. //----------------------------------------------------------------------------
  253. //   Description:    Read index and find the block id of the block containing
  254. //                          the record matching the specified key.
  255. //    Parameters:    hlf        Logical file handle
  256. //                        pbKey        Key data
  257. //                        cbKey        Size of key
  258. //                        plBlock    If not null, this variable recieves the id of the
  259. //                                    block which was read.
  260. //       Returns:    TRUE if successful.
  261. //----------------------------------------------------------------------------
  262. BOOL FN_E DioReadIndex(HLF hlf, PBYTE pbKey, SIZET cbKey, PLONG plBlock)
  263. {
  264.     HLF hlfNext;
  265.     PBYTE pbBlock;
  266.     LONG lBlock;
  267.     SIZET cBlock;
  268.  
  269.     //
  270.     //    First, perform a bunch of parameter validation in case something
  271.     //    has failed.
  272.     //
  273.     Assert(hlf >= 0 && hlf < MAX_LOGICAL_FILES);
  274.     Assert(di.logical[hlf].fUsed);
  275.     Assert(di.logical[hlf].usBlockSize);
  276.     Assert(di.logical[hlf].usType == DFT_ISAM_DATA);
  277.     Assert(di.logical[hlf].hlfNext >= 0);
  278.     Assert((di.logical[hlf].fpos % (FPOS)di.logical[hlf].usBlockSize) == 0);
  279.     Assert(pbKey && cbKey);
  280.     Assert(plBlock);
  281.     //
  282.     //    The data file pointer points to the top level isam index.
  283.     //    Read down the isam tree from the top until the bottom level.
  284.     //
  285.     hlfNext = di.logical[hlf].hlfNext;
  286.     lBlock = 0;
  287.     while (hlfNext >= 0)
  288.         {
  289.         if (!DioSeekBlock(hlfNext, lBlock)
  290.         || !DioReadBlock(hlfNext, NULL, &pbBlock, NULL))
  291.             return FALSE;
  292.  
  293.         cBlock = (SIZET)di.logical[hlfNext].usBlockSize;
  294.         DioReadSearch(pbBlock, cBlock, pbKey, cbKey, &lBlock);
  295.         hlfNext = di.logical[hlfNext].hlfNext;
  296.         }
  297.     *plBlock = lBlock;
  298.     return TRUE;
  299. }
  300.  
  301.  
  302. //----------------------------------------------------------------------------
  303. //   Description:    Search trough a block for a specified key.
  304. //    Parameters:    pb            Block to search 
  305. //                        cb            Size of block
  306. //                        pbKey        Key data
  307. //                        cbKey        Size of key
  308. //                        plBlock    Variable to recieve block to read next.
  309. //       Returns:    
  310. //----------------------------------------------------------------------------
  311. static VOID FN_L DioReadSearch(PBYTE pb, SIZET cb, PBYTE pbKey, SIZET cbKey, PLONG plBlock)
  312. {
  313.     PISAMENTRY pe1, pe2;
  314.     int rc;
  315.    SIZET cbEntry;
  316.  
  317.     pe1 = (PISAMENTRY)pb;                    // Is it the first key?
  318.     Assert((size_t)((PBYTE)&pe1->lBlock - pb) == 1);
  319.     Assert(sizeof(ISAMENTRY) == sizeof(BYTE) + sizeof(LONG) + ISAM_KEY_LEN);
  320.     rc = memcmp(pbKey, pe1->bKey, MIN(cbKey, (SIZET)pe1->bSize));
  321.     if (rc < 0 || (rc == 0 && (SIZET)pe1->bSize >= cbKey))
  322.         {
  323.         *plBlock = pe1->lBlock;
  324.         return ;
  325.         }
  326.     for (;;)
  327.         {
  328.         cbEntry = sizeof(ISAMENTRY) - ISAM_KEY_LEN + pe1->bSize;
  329.         Assert(cbEntry <= cb);                // Should never happen
  330.         if (cbEntry == cb)                    // Last key in this block
  331.             break;
  332.  
  333.         cb -= cbEntry;
  334.         pb += cbEntry;                            // Move to next key
  335.         pe2 = (PISAMENTRY)pb;
  336.         if (pe2->bSize == 0)                    // Another way of specifying the last
  337.             break;                                //  key in a block
  338.         //
  339.         //    If the inquiry key is less than the next key select this block.
  340.         //    If it is equal, and the index key is >= select this block. This 
  341.         //    covers case like NE_LINDSAY --> NE_L where the key is not unique
  342.         //    and may span blocks.
  343.         //
  344.         rc = memcmp(pbKey, pe2->bKey, MIN(cbKey, (SIZET)pe2->bSize));
  345.         if (rc < 0 || (rc == 0 && (SIZET)pe2->bSize >= cbKey))
  346.             break;                                // Less than next key, so done!
  347.         pe1 = pe2;
  348.         }
  349.     *plBlock = pe1->lBlock;
  350.     return ;
  351. }
  352. //----------------------------------------------------------------------------
  353. //------------------------------- End of File --------------------------------
  354. //----------------------------------------------------------------------------
  355.